package com.taursys.model; import java.text.Format; import java.text.MessageFormat; import com.taursys.util.DataTypes; import com.taursys.util.UnsupportedDataTypeException; import com.taursys.util.UnsupportedConversionException; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.text.ParseException; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.lang.IllegalAccessException; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.beans.IntrospectionException; import com.taursys.util.DataTypes; import java.util.StringTokenizer; /** * Sets the name of the property in the valueObject to use. This is the * property that get/setObject and get/setText methods will access. The * property name should follow JavaBean conventions. * <p> * Example: propertyName="color": then it expects getColor and setColor * will be the method names in the valueObject. * <p> * NOTE: Setting the propertyName will only have effect BEFORE the * setAccessorMethods process is invoked. Once the accessor methods have * been set, subsequent changes to this property will have no effect. */ public class PropertyAdapter { private String propertyName; private int javaDataType = DataTypes.TYPE_UNDEFINED; private java.lang.reflect.Method writeMethod; private java.lang.reflect.Method[] readMethods; public PropertyAdapter(Class valueObjectClass, String propertyName) throws IntrospectionException, InvocationTargetException, IllegalAccessException { setAccessorMethods(valueObjectClass, propertyName); } // *********************************************************************** // * INITIALIZATION METHODS // *********************************************************************** /** * Sets the javaDataType, readMethods and writeMethod properties. * The valueObject and propertyName must be valid before invoking this * method, otherwise an IntrospectionException will be thrown. * The readMethods or writeMethod may be null if the valueObject does * not have a cooresponding get or set method. This method uses reflection * and draws information from the valueObject's BeanInfo and PropertyDescriptors. * <p> * This method also sets a flag to indicate that the valueObject has been * introspected and the accessor methods are set. */ private void setAccessorMethods(Class c, String propertyName) throws IntrospectionException, InvocationTargetException, IllegalAccessException { if (c == null) throw new IntrospectionException("Value Object class is null"); if (propertyName == null || propertyName.length() == 0) throw new IntrospectionException("propertyName is null or blank"); this.propertyName = propertyName; StringTokenizer tokenizer = new StringTokenizer(propertyName, "."); int count = tokenizer.countTokens() ; readMethods = new Method[count]; PropertyDescriptor prop = null; for (int i = 0; i < count ; i++) { String propName = tokenizer.nextToken(); prop = getProperty(c, propName); readMethods[i] = prop.getReadMethod(); c = prop.getPropertyType(); } javaDataType = DataTypes.getDataType(c.getName()); writeMethod = prop.getWriteMethod(); } /** * Searches the given class for the given property name and returns the PropertyDescriptor. * Throws IntrospectionException if property is not found. */ protected PropertyDescriptor getProperty(Class c, String propName) throws IntrospectionException { BeanInfo info = Introspector.getBeanInfo(c); PropertyDescriptor[] props = info.getPropertyDescriptors(); for( int i=0 ; i < props.length ; i++ ) { if (props[i].getName().equals(propName)) { return props[i]; } } throw new IntrospectionException("Property " + propName + " is not found in " + c.getName()); } // *********************************************************************** // * TEXT PARSE/FORMAT ROUTINES // *********************************************************************** /** * Returns the accessed Object as a String value using Format if defined. * If the accessed Object is null, it will return an empty String (""). */ public String getText(Object valueObject, Format format) throws IntrospectionException, InvocationTargetException, IllegalAccessException { Object value = getPropertyValue(valueObject); if (value == null) return ""; if (format == null) return DataTypes.format(javaDataType, value); else if (format instanceof MessageFormat) return ((MessageFormat)format).format(new Object[] {value}); else return format.format(value); } /** * Sets the accessed Object from the given String value to DataType using Format(if defined) to parse. * If the given String value is null or empty (""), the accessed Object is * set to null. */ public void setText(Object target, String value, Format format) throws IntrospectionException, InvocationTargetException, IllegalAccessException, ParseException, UnsupportedDataTypeException, UnsupportedConversionException { if (value == null || value.length() == 0) setPropertyValue(target, null); else if (format == null) setPropertyValue(target, DataTypes.parse(javaDataType, value)); else if (format instanceof MessageFormat) { Object[] values = ((MessageFormat)format).parse(value); setPropertyValue(target, DataTypes.convert(javaDataType, values[0])); } else setPropertyValue(target, DataTypes.convert(javaDataType, format.parseObject(value))); } // *********************************************************************** // * PROPERTY VALUE ACCESSOR METHODS // *********************************************************************** /** * Returns a property value from the valueObject based on the propertyName. * The valueObject and propertyName properties must be defined before * you invoke this method, and the valueObject must have a getter for * the propertyName, otherwise IntrospectionException will be raised. * This method will invoke the setAccessorMethods method if it has not * yet been invoked. */ public Object getPropertyValue(Object valueObject) throws IntrospectionException, InvocationTargetException, IllegalAccessException { Object obj = valueObject; for (int i = 0; obj != null && i < readMethods.length; i++) { if (readMethods[i] == null) throw new IntrospectionException("Property " + propertyName + " has no get method defined in " + obj.getClass().getName()); obj = readMethods[i].invoke(obj, new Object[] {}); } return obj; } /** * Sets a property of the valueObject to the given value based on the propertyName. * The valueObject and propertyName properties must be defined before * you invoke this method, and the valueObject must have a setter for * the propertyName, otherwise IntrospectionException will be raised. * This method will invoke the setAccessorMethods method if it has not * yet been invoked. */ public void setPropertyValue(Object valueObject, Object value) throws IntrospectionException, InvocationTargetException, IllegalAccessException { if(valueObject == null) throw new IntrospectionException("Value object is null"); if(writeMethod == null) throw new IntrospectionException("Property " + propertyName + " has no set method defined in " + valueObject.getClass().getName()); Object target = valueObject; int count = readMethods.length -1; for (int i = 0; target != null && i < count ; i++) { if (readMethods[i] == null) throw new IntrospectionException("Property " + propertyName + " has no get method defined in " + target.getClass().getName()); target = readMethods[i].invoke(target, new Object[] {}); } writeMethod.invoke(target, new Object[] {value}); } // *********************************************************************** // * PROPERTY ACCESSOR METHODS // *********************************************************************** /** * Returns the name of the property in the valueObject to use. This is the * property that get/setObject and get/setText methods will access. The * property name should follow JavaBean conventions. * <p> * Example: propertyName="color": then it expects getColor and setColor * will be the method names in the valueObject. */ public String getPropertyName() { return propertyName; } /** * Returns the Methods used to get/read the target property. * This value is set by setAccessorMethods which is invoked * automatically by the set/getObject or setText methods. */ protected java.lang.reflect.Method[] getReadMethods() { return readMethods; } /** * Returns the Method used to get/read the target property. * This value is set by setAccessorMethods which is invoked * automatically by the set/getObject or setText methods. */ protected java.lang.reflect.Method getWriteMethod() { return writeMethod; } }